package com.zyk.scaffold.oauth.rpc;

import com.zyk.scaffold.oauth.dto.TokenInfoDTO;
import com.zyk.scaffold.oauth.enums.OauthErrorCodeEnum;
import com.zyk.scaffold.oauth.framework.OauthManager;
import com.zyk.scaffold.oauth.framework.domain.AccessToken;
import com.zyk.scaffold.oauth.framework.domain.Subject;
import com.zyk.scaffold.oauth.framework.exception.OauthException;
import com.zyk.scaffold.common.exception.BusinessException;
import com.zyk.scaffold.common.utils.MapUtils;
import com.zyk.scaffold.user.dto.UserInfoDTO;
import com.zyk.scaffold.user.rpc.UserRpcService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Collections;
import java.util.List;
import java.util.Map;

@DubboService
@Slf4j
public class OauthRpcServiceImpl implements OauthRpcService {

    @Autowired
    private OauthManager oauthManager;

    @DubboReference
    private UserRpcService userRpcService;

    @Override
    public TokenInfoDTO analysisAccessToken(String accessToken) throws BusinessException {
        AccessToken accessTokenObj;
        try{
            accessTokenObj = oauthManager.getAccessToken(accessToken);
        }catch (OauthException ex){
            throw new BusinessException(OauthErrorCodeEnum.AUTHORIZATION_ERROR, ex);
        }
        if(accessTokenObj == null){
            return null;
        }
        Map<String, Object> data = accessTokenObj.getData();
        TokenInfoDTO tokenInfoDTO = new TokenInfoDTO();
        tokenInfoDTO.setUserId(MapUtils.getLong(data, "userId"));
        tokenInfoDTO.setNickName(MapUtils.getString(data, "nickName"));
        tokenInfoDTO.setTenantCode(MapUtils.getString(data, "tenantCode"));
        tokenInfoDTO.setTenantName(MapUtils.getString(data, "tenantName"));
        tokenInfoDTO.setPhone(MapUtils.getString(data, "phone"));
        tokenInfoDTO.setEmail(MapUtils.getString(data, "email"));
        tokenInfoDTO.setPrivateKey(MapUtils.getString(data, "privateKey"));
        tokenInfoDTO.setPublicKey(MapUtils.getString(data, "publicKey"));
        tokenInfoDTO.setCreateTime(MapUtils.getString(data, "createTime"));
        tokenInfoDTO.setJwt(MapUtils.getString(data, "jwt"));
        List<Map<String, Object>> menuApis = (List<Map<String, Object>>)MapUtils.getObject(data, "menuApis");
        if (menuApis == null) {
            menuApis = Collections.emptyList();
        }
        tokenInfoDTO.setMenuApis(menuApis);

        List<Map<String, Object>> menuFunctions = (List<Map<String, Object>>)MapUtils.getObject(data, "menuFunctions");
        if (menuFunctions == null) {
            menuFunctions = Collections.emptyList();
        }
        tokenInfoDTO.setMenuFunctions(menuFunctions);
        return tokenInfoDTO;
    }

    @Override
    public Boolean loginOutByUserId(Long userId) {
        UserInfoDTO userInfoDTO = userRpcService.getUserByUserId(userId);
        String account = userInfoDTO.getAccount();
        return loginOutByAccount(account);
    }

    @Override
    public Boolean loginOutByAccount(String account) {
        Subject subject = oauthManager.getTokenService().getTokenStore().getSubject(account);
        if(subject == null){
            return Boolean.TRUE;
        }
        String accessToken = subject.getAccessToken();
        return loginOutByAccessToken(accessToken);
    }

    @Override
    public Boolean loginOutByAccessToken(String accessToken) {
        Boolean logout;
        try {
            logout = oauthManager.logout(accessToken);
        } catch (OauthException ex) {
            throw new BusinessException(OauthErrorCodeEnum.LOGIN_OUT_ERROR, ex);
        }
        return logout;
    }
}
